public class Test {
    public static void main(String[] args) throws Exception {
        ShapeGroup group = new ShapeGroup();
        group.add(new Circle(3));
        group.add(new Rectangle(4, 5));

        // 已有操作：面积
        group.accept(new AreaVisitor());

        // 扩展操作：周长
        group.accept(new PerimeterVisitor());
    }
}
// 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
// 访问者模式（Visitor）是一种操作一组对象的操作，它的目的是不改变对象的定义，但允许新增不同的访问者，来定义新的操作


/* ---------- 元素接口 ---------- */
interface Shape {
    void accept(Visitor v); // 接待访问者
}

/* ---------- 具体元素 ---------- */
class Circle implements Shape {
    double radius;

    Circle(double r) {
        this.radius = r;
    }

    public void accept(Visitor v) {
        v.visitCircle(this);
    }
}

class Rectangle implements Shape {
    double width, height;

    Rectangle(double w, double h) {
        this.width = w;
        this.height = h;
    }

    public void accept(Visitor v) {
        v.visitRectangle(this);
    }
}

/* ---------- 对象结构 ---------- */
class ShapeGroup {
    private java.util.List<Shape> shapes = new java.util.ArrayList<>();

    void add(Shape s) {
        shapes.add(s);
    }

    void accept(Visitor v) {
        shapes.forEach(s -> s.accept(v));
    }
}

/* ---------- 访问者接口 ---------- */
interface Visitor {
    void visitCircle(Circle c);

    void visitRectangle(Rectangle r);
}

/* ---------- 具体访问者：面积 ---------- */
class AreaVisitor implements Visitor {
    public void visitCircle(Circle c) {
        System.out.println("Circle area = " + (Math.PI * c.radius * c.radius));
    }

    public void visitRectangle(Rectangle r) {
        System.out.println("Rectangle area = " + (r.width * r.height));
    }
}

/* ---------- 具体访问者：周长 ---------- */
class PerimeterVisitor implements Visitor {
    public void visitCircle(Circle c) {
        System.out.println("Circle perimeter = " + (2 * Math.PI * c.radius));
    }

    public void visitRectangle(Rectangle r) {
        System.out.println("Rectangle perimeter = " + (2 * (r.width + r.height)));
    }
}